import { AuthError, authenticateRequest } from "@/lib/auth/server"; import { GateFileError, getGateFileContent } from "@/lib/chat/gate-files"; import { getOwnedAttachment } from "@/lib/db/attachments"; import { getPool } from "@/lib/db/pool"; import { getAttachmentObject } from "@/lib/storage/s3"; export const runtime = "nodejs"; const noStoreHeaders = { "Cache-Control": "no-store" }; export async function GET(request: Request, { params }: { params: Promise<{ id: string }> }): Promise { try { const user = await authenticateRequest(request); const authorization = request.headers.get("Authorization"); if (!authorization) throw new AuthError(); const attachment = await getOwnedAttachment(getPool(), user.id, (await params).id); if (!attachment) { return Response.json( { error: "Вложение не найдено" }, { status: 404, headers: noStoreHeaders }, ); } const content = attachment.gateFileId ? await getGateFileContent(attachment.gateFileId, authorization, request.signal) : attachment.objectKey ? await getAttachmentObject(attachment.objectKey) : null; if (!content) throw new Error("Attachment has no storage reference"); return new Response(content, { headers: { ...noStoreHeaders, "Content-Disposition": `attachment; filename*=UTF-8''${encodeFilename(attachment.name)}`, "Content-Length": String(attachment.size), "Content-Type": attachment.contentType, "X-Content-Type-Options": "nosniff", }, }); } catch (error) { return Response.json( { error: error instanceof AuthError || (error instanceof GateFileError && error.reason === "unauthorized") ? "Unauthorized" : "Хранилище вложений временно недоступно", }, { status: error instanceof AuthError || (error instanceof GateFileError && error.reason === "unauthorized") ? 401 : 503, headers: noStoreHeaders, }, ); } } function encodeFilename(value: string): string { return encodeURIComponent(value).replace(/[!'()*]/g, (character) => `%${character.charCodeAt(0).toString(16).toUpperCase()}`, ); }